// /////////////////////////////////////////////////////////////////////////////
//
// Name:            TextureProcessor.cpp
// Author:          Michael Bartsch (ZCCdark203)
//
// Desc :           AssetProcessor for processing textures in an AssetGroup.
//
// License:         Copyright (C) 2009 Michael Bartsch and Contributors
//
//                  This program is free software: you can redistribute it
//                  and/or modify it under the terms of the zlib/libpng License.
//                  See main.cpp for conditions of distribution and use.
//
// /////////////////////////////////////////////////////////////////////////////

// Include files
#include "TextureProcessor.h"
#include "../core/GameManager.h"


// TextureProcessor class
// TextureProcessor constructor.
TextureProcessor::TextureProcessor(AssetGroup *parent)
: AssetProcessor(parent, "textures"), mIsReloading(false)
{
}

// TextureProcessor deconstructor.
TextureProcessor::~TextureProcessor()
{
    removeAssets();
}

// Gets the texture with the given filename.
ITexture* TextureProcessor::getTexture(const std::string &fileName)
{
#ifdef WIN32
	std::string tmp = fileName;
	std::transform(tmp.begin(), tmp.end(), tmp.begin(), ::tolower);
	std::map<std::string, ITexture*>::iterator it = mTextures.find(tmp);
#else
    std::map<std::string, ITexture*>::iterator it = mTextures.find(fileName);
#endif

    if(it != mTextures.end())
      return it->second;

    return NULL;
}

// Loads the mesh with the given filename.
bool TextureProcessor::loadAsset(const std::string &fileName)
{
    // Retrieve pointers to sub-sytems of the Irrlicht engine.
    IFileSystem *fileSystem = GameManager::Instance()->getDevice()->getFileSystem();
    IVideoDriver *pDriver = GameManager::Instance()->getDriver();

    // Change the working directory to the textures directory.
    std::string workingDir = (fileSystem->getWorkingDirectory()).c_str();

    if(!fileSystem->changeWorkingDirectoryTo( (pParent->getBaseDir()).c_str() ) )
      return false;

    if(!fileSystem->changeWorkingDirectoryTo("./textures/"))
      return false;

    // Read the texture.
    ITexture *texture = pDriver->getTexture(fileName.c_str());

    if(texture)
    {
       // Store texture.
       mTextures[fileName] = texture;
       texture->grab();

       // Remove the texture from the internal driver.
       GameManager::Instance()->getDriver()->removeTexture(texture);

       // Handle events.
       if(mIsReloading)
         pParent->emitEvent(std::string("textures/") + fileName, texture);

       else
         pParent->createEventSlot(std::string("textures/") + fileName);
    }

    // Clean up.
    fileSystem->changeWorkingDirectoryTo(workingDir.c_str());

    return (texture) ? true : false;
}

// Loads the meshes associated with this asset group.
void TextureProcessor::loadAssets()
{
    // Retrieve pointers to sub-sytems of the Irrlicht engine.
    IFileSystem *fileSystem = GameManager::Instance()->getDevice()->getFileSystem();
    IVideoDriver *pDriver = GameManager::Instance()->getDriver();

    // Change the working directory to the textures directory.
    std::string workingDir = (fileSystem->getWorkingDirectory()).c_str();

    if(!fileSystem->changeWorkingDirectoryTo( (pParent->getBaseDir()).c_str() ) )
      return;

    if(!fileSystem->changeWorkingDirectoryTo("./textures/"))
      return;

    // Read the textures.
    IFileList *fileList = fileSystem->createFileList();

    for(u32 i = 0; i < fileList->getFileCount(); i++)
    {
        // Get file name.
        std::string fileName = (fileList->getFileName(i)).c_str();

        if(fileName == ".." || fileName == ".")
          continue;

        // Load the mesh.
        ITexture *texture = pDriver->getTexture(fileName.c_str());

        if(texture)
        {
           // Store texture.
           mTextures[fileName] = texture;
           texture->grab();

           // Remove the texture from the internal driver.
           GameManager::Instance()->getDriver()->removeTexture(texture);

           // Handle events.
           if(mIsReloading)
             pParent->emitEvent(std::string("textures/") + fileName, texture);

           else
             pParent->createEventSlot(std::string("textures/") + fileName);

        }
    }

    // Clean up.
    fileList->drop();

    fileSystem->changeWorkingDirectoryTo(workingDir.c_str());
}

// Reloads the asset with the given filename.
bool TextureProcessor::reloadAsset(const std::string &fileName)
{
    mIsReloading = true;

    removeAsset(fileName);
    bool succeeded = loadAsset(fileName);

    mIsReloading = false;

    return succeeded;
}

// Reloads all assets.
void TextureProcessor::reloadAssets()
{
    mIsReloading = true;

    removeAssets();
    loadAssets();

    mIsReloading = false;
}

// Removes the asset with the given filename.
bool TextureProcessor::removeAsset(const std::string &fileName)
{
    // Try to find the given texture.
#ifdef WIN32
	std::string tmp = fileName;
	std::transform(tmp.begin(), tmp.end(), tmp.begin(), ::tolower);
    std::map<std::string, ITexture*>::iterator it = mTextures.find(tmp);
#else
    std::map<std::string, ITexture*>::iterator it = mTextures.find(fileName);
#endif

    // Did we find the texture?
    if(it != mTextures.end())
    {
       // Handle events.
       if(!mIsReloading)
       {
          std::string slotName = std::string("textures/") + it->first;

          pParent->emitEvent(slotName, NULL);
          pParent->removeEventSlot(slotName);
       }

       // Delete the texture.
       ITexture *texture = it->second;
       texture->drop();
       mTextures.erase(it);

       return true;
    }

    // We didn't find the texture.
    else return false;
}

// Removes all asssets.
void TextureProcessor::removeAssets()
{
    // Delete the textures.
    std::map<std::string, ITexture*>::iterator it;

    for(it = mTextures.begin(); it != mTextures.end(); it++)
    {
       // Handle events.
       if(!mIsReloading)
       {
          std::string slotName = std::string("textures/") + it->first;

          pParent->emitEvent(slotName, NULL);
          pParent->removeEventSlot(slotName);
       }

       // Delete the texture.
       ITexture *texture = it->second;
       texture->drop();
    }

    // Clear the texture map.
    mTextures.clear();
}

// Creates a new TextureProcessor.
AssetProcessor* TextureProcessor::createProcessor(AssetGroup *parent)
{
    return new TextureProcessor(parent);
}

// End of File
